﻿using Microsoft.Extensions.Options;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using Volo.Abp.DependencyInjection;

namespace Xms.Abp.Caching;

public abstract class CacheContext<TCacheContext>
    where TCacheContext: CacheContext<TCacheContext>
{
    private ConcurrentDictionary<string, object> KeyValueCaches { get; } = new();
    private ConcurrentDictionary<string, object> HashCaches { get; } = new();
    private ConcurrentDictionary<string, IGeoCache> GeoCaches { get; } = new();
    protected ICacheProvider CacheProvider { get; }
    protected IAbpLazyServiceProvider LazyServiceProvider { get; }
    public CacheContext(
        IAbpLazyServiceProvider lazyServiceProvider,
        IOptions<DistributedCacheProviderOptions> optionsAccessor,
        IEnumerable<ICacheProvider<TCacheContext>> cacheProviders)
    {
        LazyServiceProvider = lazyServiceProvider;
        CacheProvider = cacheProviders.FirstOrDefault(r => r.Name == (optionsAccessor.Value.ProviderName ?? "Default"));
    }
    protected IGeoCache Geo([CallerMemberName]string name = null)
    {
        return GeoCaches.GetOrAdd(name, n => new GeoCache(LazyServiceProvider, CacheProvider, n));
    }

    protected IHashCache<T> Hash<T>([CallerMemberName] string name = null)
    {
        return (IHashCache<T>)HashCaches.GetOrAdd(name, n => new HashCache<T>(LazyServiceProvider, CacheProvider, n));
    }

    protected IKeyValueCache<T> KeyValue<T>([CallerMemberName] string name = null)
    {
        return (IKeyValueCache<T>)KeyValueCaches.GetOrAdd(name, n => new KeyValueCache<T>(LazyServiceProvider, CacheProvider, n));
    }

    protected IHashCache<string> Hash([CallerMemberName] string name = null)
    {
        return (IHashCache<string>)HashCaches.GetOrAdd(name, n => new HashCache<string>(LazyServiceProvider, CacheProvider, n));
    }

    protected IKeyValueCache<string> KeyValue([CallerMemberName] string name = null)
    {
        return (IKeyValueCache<string>)KeyValueCaches.GetOrAdd(name, n => new KeyValueCache<string>(LazyServiceProvider, CacheProvider, n));
    }
}